package com.hitqz.robot.driver.netty.strategy;

import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.google.common.util.concurrent.RateLimiter;
import com.hitqz.robot.api.common.dto.robot.RobotOnlineEventDto;
import com.hitqz.robot.driver.dto.GfRobotStatus;
import com.hitqz.robot.driver.netty.protocol.message.GfMessage;
import com.hitqz.robot.driver.util.GfCacheUtil;
import com.hitqz.robot.driver.util.GfToolkit;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.InetSocketAddress;
import java.util.Objects;
import java.util.Optional;

/**
 * 消息解析，只做信息保存或者发布事件，不做业务逻辑处理
 */
@Slf4j
public class Gf79Strategy implements GfMessageHandlerStrategy {

    private final static RateLimiter logLimiter = RateLimiter.create(1);

    @Override
    public void handle(ChannelHandlerContext ctx, GfMessage message) {
        // 获取消息中的数据
        byte[] data = message.getData();
        int mainCmd = data[0] & 0xFF;//转换为无符号
        int subCmd = data[1] & 0xFF;//转换为无符号
        boolean reslut = true;
        // 分配 ByteBuf 并将数据写入
        ByteBuf buffer = ctx.alloc().buffer(data.length);
        buffer.writeBytes(data);
        try {
            mainCmd = buffer.readByte() & 0xFF;
            subCmd = buffer.readByte() & 0xFF;
            //机器人编码
            byte[] sn = new byte[4];
            buffer.readBytes(sn);
            String robotSerial = HexUtil.encodeHexStr(sn);
            switch (subCmd) {
                case 0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09 -> {
                    reslut = buffer.readByte() == (byte)0x00;
                }
                case 0x11->{
                    //获取机器设备工作状态(含返回实时转速) 0x79+0x11
                    short reachStatus = buffer.readShortLE();//上报心跳间隔时间 单位：毫秒
                    int qdlSpeed = buffer.readIntLE();//驱动轮速度（R/min） 4byte
                    int gsSpeed = buffer.readIntLE();//滚刷速度（R/min） 4byte
                    float qdlMotorCurrent = BigDecimal.valueOf(buffer.readIntLE()).divide(BigDecimal.valueOf(100).setScale(2,RoundingMode.HALF_UP)).floatValue();//驱动轮电机电流（A 传输比例100） 4byte
                    float gsMotorCurrent = BigDecimal.valueOf(buffer.readIntLE()).divide(BigDecimal.valueOf(100).setScale(2,RoundingMode.HALF_UP)).floatValue();;//滚刷电机电流（A 传输比例100） 4byte
                    int qdlMotorDis = buffer.readIntLE();//驱动轮电机里程计 4byte
                    int gsMotorDis = buffer.readIntLE();//滚刷电机里程计 4byte
                    int qdlMotorErr = buffer.readIntLE();//驱动轮电机故障状态 4byte
                    int gsMotorErr = buffer.readIntLE();//滚刷电机故障状态 4byte
                    short power = buffer.readShortLE();//电量百分比（0%-100%）
                    float voltage =BigDecimal.valueOf(buffer.readShortLE()).divide(BigDecimal.valueOf(100).setScale(2,RoundingMode.HALF_UP)).floatValue();//电压（传输比例100）：V
                    float current = BigDecimal.valueOf(buffer.readShortLE()).divide(BigDecimal.valueOf(100).setScale(2,RoundingMode.HALF_UP)).floatValue();//电流（传输比例100）：A
                    float ratedCapacity = BigDecimal.valueOf(buffer.readShortLE()).divide(BigDecimal.valueOf(10).setScale(2,RoundingMode.HALF_UP)).floatValue();//额定容量（传输比例10）
                    short temperature = buffer.readShortLE();//温度（传输比例1）
                    short currentDirection = buffer.readShortLE();//电流方向（0是放电，1为充电）
                    short directionInfo = buffer.readShortLE();//方向信息 0x01：向左正向方向 0x02：向右反向方向
                    byte workNum = buffer.readByte();//当前工作次数
                    byte workStatus = buffer.readByte();//机器人工作状态 0x00：机器空闲  0x01：机器工作 0x10：电机堵转 0x11：通讯异常 0x12：电量过低 0x20：进入程序状态 0x21：程序升级中  0x22：程序升级完成
                    byte chipTemperature = buffer.readByte();//芯片温度
                    byte psStatus = buffer.readByte();//光电传感器状态
                    byte psErrStatus = buffer.readByte();//光电传感器堵转触发状态
                    int psRunTime = buffer.readIntLE();//光电避障运行计数时间 4byte
                    byte psOpenStatus = buffer.readByte();//光电避障开关状态 0x01：设置开启 0x02：设置关闭
                    int psSetTime = buffer.readIntLE();//光电避障上位机设置时间 4byte
                    byte leftProximitySwitchTriggeringStatus = buffer.readByte();//左边接近开关触发状态（起点） 0x00：接近开关触发  0x01：接近开关未触发
                    byte rightProximitySwitchTriggeringStatus = buffer.readByte();//右边接近开关触发状态（终点） 0x00：接近开关触发 0x01：接近开关未触发
                    float robotSpeed = BigDecimal.valueOf(buffer.readShortLE()).divide(BigDecimal.valueOf(100000).setScale(3,RoundingMode.HALF_UP)).floatValue();//机器人行走速度换算 单位m/s（放大100000倍） 4byte
                    byte forwardStatus = buffer.readByte();//正向运行（机器从左向右运行）  0x00：机器未正向运行  0x01：机器正在正向运行
                    byte reverseStatus = buffer.readByte();//逆向运行（机器从右向左运行） 0x00：机器未逆向运行 0x01：机器正在逆向运行
                    byte putterUpLimit = buffer.readByte();//推杆上限位 0x00：未触发 0x01：触发
                    byte putterDownLimit = buffer.readByte();//推杆下限位 0x00：未触发 0x01：触发
                    byte putterPE0Enable = buffer.readByte();//推杆PE0使能状态 0x00：未使能 0x01：使能
                    byte putterPE1Enable = buffer.readByte();//推杆PE0使能状态 0x00：未使能 0x01：使能
                    byte cameraAndWiperEnable = buffer.readByte();//相机和雨刷使能状态 0x00：未使能 0x01：使能
                    byte wiperWorkStatus = buffer.readByte();//雨刷工作状态 0x00：雨刷空闲 0x01：雨刷正在工作
                    byte runningDriverEnable = buffer.readByte();//行走电机、编码器、漫反射使能状态 0x00：未使能 0x01：使能
                    byte gsDriverEnable = buffer.readByte();//滚刷电机使能状态 0x00：未使能 0x01：使能
                    byte ipcEnable = buffer.readByte();//工控机使能状态 0x00：未使能 0x01：使能
                    short panelSn = buffer.readShortLE();//光伏板点位 起点为0
                    int mileage = buffer.readIntLE();//编码器编码值（起点为0，会有一定误差）
                    GfRobotStatus gfRobotStatus = GfRobotStatus.builder().robotSerial(robotSerial).reachStatus(reachStatus).qdlSpeed(qdlSpeed)
                            .gsSpeed(gsSpeed).qdlMotorCurrent(qdlMotorCurrent).gsMotorCurrent(gsMotorCurrent)
                            .qdlMotorDis(qdlMotorDis).gsMotorDis(gsMotorDis).qdlMotorErr(qdlMotorErr).gsMotorErr(gsMotorErr)
                            .power(power).voltage(voltage).current(current).ratedCapacity(ratedCapacity)
                            .temperature(temperature).currentDirection(currentDirection).directionInfo(directionInfo)
                            .workNum(workNum).workStatus(workStatus).psStatus(psStatus).psErrStatus(psErrStatus)
                            .chipTemperature(chipTemperature).psRunTime(psRunTime).psOpenStatus(psOpenStatus).forwardStatus(forwardStatus)
                            .psSetTime(psSetTime).leftProximitySwitchTriggeringStatus(leftProximitySwitchTriggeringStatus)
                            .rightProximitySwitchTriggeringStatus(rightProximitySwitchTriggeringStatus).robotSpeed(robotSpeed)
                            .reverseStatus(reverseStatus).putterUpLimit(putterUpLimit).putterDownLimit(putterDownLimit).putterPE0Enable(putterPE0Enable)
                            .putterPE1Enable(putterPE1Enable).cameraAndWiperEnable(cameraAndWiperEnable).wiperWorkStatus(wiperWorkStatus)
                            .runningDriverEnable(runningDriverEnable).gsDriverEnable(gsDriverEnable).ipcEnable(ipcEnable).panelSn(panelSn).mileage(mileage).build();
                    if (logLimiter.tryAcquire(15)) {
                        log.info("[gf]{},status:{}", robotSerial, gfRobotStatus);
                    }
                    GfCacheUtil.put(GfCacheUtil.KEY_ROBOT_STATUS,gfRobotStatus);
                }
                case 0x12->{
                    GfRobotStatus lastStatus = Optional.ofNullable((GfRobotStatus) GfCacheUtil.get(GfCacheUtil.KEY_ROBOT_STATUS)).orElse(GfRobotStatus.builder().build());
                    if (StrUtil.isBlank(lastStatus.getRobotSerial())){
                        log.info("[gf] get robot serial number:{}", robotSerial);
                    }
                    if (Objects.equals(robotSerial,GfToolkit.serialNumber)){
                        //保存通道
                        boolean isRelay  = buffer.readableBytes()>1;
                        log.info("[gf] get isRelay status:{}",isRelay);
                        if (isRelay){
                            //继电器通道
                            GfToolkit.relayCtx = ctx;
                            log.info("[gf]save relay ctx,{}",ctx);
                        }else {
                            GfToolkit.ctx = ctx;
                            log.info("[gf]save chip ctx,{}",ctx);
                        }
                        log.info("[gf] get ChannelHandlerContext:{} success",ctx);
                        //上线状态
                        RobotOnlineEventDto dto = new RobotOnlineEventDto();
                        dto.setOnlineStatus(1);
                        SpringUtil.getApplicationContext().publishEvent(dto);
                    }else {
                        InetSocketAddress remoteAddress = (InetSocketAddress) ctx.channel().remoteAddress();
                        String clientIp = remoteAddress.getAddress().getHostAddress();
                        GfToolkit.blacklist.add(clientIp);
                        ctx.close();
                        log.warn("[gf]serial number wrong ,block ip:{}",clientIp);
                    }
                }
            }
            GfToolkit.release(message, true, reslut);
        } catch (Exception e) {
            log.error("[gf]deal  {}{}-message error,{}", String.format("%02x", mainCmd), String.format("%02x", subCmd), e.getMessage());
        } finally {
            // 确保 ByteBuf 在使用完后释放，防止内存泄漏
            buffer.release();
        }
    }


}
